Codeforces Round #271 (Div. 2)题解【ABCDEF】
Codeforces Round #271 (Div. 2)
A - Keyboard
题意
给你一个字符串,问你这个字符串在键盘的位置往左边挪一位,或者往右边挪一位字符,这个字符串是什么样子
题解
模拟一下就好了
代码
#include<bits/stdc++.h>
using namespace std;
string s[3];
map<char,int>r,c;
char ss[2][107];
int main()
{
s[0]="qwertyuiop";
s[1]="asdfghjkl;";
s[2]="zxcvbnm,./";
for(int i=0;i<3;i++){
for(int j=0;j<s[0].size();j++){
r[s[i][j]]=i;
c[s[i][j]]=j;
}
}
scanf("%s%s",ss[0],ss[1]);
if(ss[0][0]=='R'){
int len = strlen(ss[1]);
for(int i=0;i<len;i++)
printf("%c",s[r[ss[1][i]]][c[ss[1][i]]-1]);
}
else{
int len = strlen(ss[1]);
for(int i=0;i<len;i++)
printf("%c",s[r[ss[1][i]]][c[ss[1][i]]+1]);
}
}
B. Worms
题意
给你一个a[i]数组,表示每个区间所能管辖的范围。
第一个区间为[1,a[1]],第二个为[a[1]+1,a[1]+a[2]],然后依次下去……
然后有m个询问,每次给你一个x,问你这个x在哪个区间里面
题解
区间管辖范围呈现单调,所以我们直接二分找到区间就好了嘛
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
int r[maxn],n,m,a[maxn];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
r[i]=r[i-1]+a[i];
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
int x;
scanf("%d",&x);
int L=1,R=n,ans=n;
while(L<=R){
int mid=(L+R)/2;
if(r[mid]<x)L=mid+1;
else R=mid-1,ans=mid;
}
cout<<ans<<endl;
}
}
C - Captain Marmot
题意
有t次询问,每次询问给你四个点,以及每个点相互对应的旋转中心。
你可以逆时针旋转,你要求使得所有点的旋转次数和最少,然后构成一个正方形,问你旋转次数是多少。
题解
暴力嘛,反正数据范围这么小,判断直角就用dot product就好了嘛
代码
#include<bits/stdc++.h>
using namespace std;
int x[4],y[4],a[4],b[4];
int p[4][4][2];
vector<int>X,Y;
int dis(int x1,int y1,int x2,int y2){
return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}
int dot(int x1,int y1,int x2,int y2,int x3,int y3){
return (x1-x3)*(x2-x3)+(y1-y3)*(y2-y3);
}
void solve(){
for(int i=0;i<4;i++)
scanf("%d%d%d%d",&x[i],&y[i],&a[i],&b[i]);
for(int i=0;i<4;i++){
p[i][0][0]=x[i];
p[i][0][1]=y[i];
for(int j=1;j<4;j++){
int x=p[i][j-1][0]-a[i];
int y=p[i][j-1][1]-b[i];
p[i][j][0]=-y+a[i];
p[i][j][1]=x+b[i];
}
}
int Ans = 10000;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
for(int k=0;k<4;k++){
for(int t=0;t<4;t++){
X.clear(),Y.clear();
X.push_back(p[0][i][0]);
X.push_back(p[1][j][0]);
X.push_back(p[2][k][0]);
X.push_back(p[3][t][0]);
Y.push_back(p[0][i][1]);
Y.push_back(p[1][j][1]);
Y.push_back(p[2][k][1]);
Y.push_back(p[3][t][1]);
vector<int>tmp;
for(int ii=0;ii<4;ii++)
tmp.push_back(ii);
int flag=0;
do{
int dis1 = dis(X[tmp[0]],Y[tmp[0]],X[tmp[1]],Y[tmp[1]]);
int dis2 = dis(X[tmp[1]],Y[tmp[1]],X[tmp[2]],Y[tmp[2]]);
int dis3 = dis(X[tmp[2]],Y[tmp[2]],X[tmp[3]],Y[tmp[3]]);
int dis4 = dis(X[tmp[3]],Y[tmp[3]],X[tmp[0]],Y[tmp[0]]);
int dot1 = dot(X[tmp[0]],Y[tmp[0]],X[tmp[2]],Y[tmp[2]],X[tmp[1]],Y[tmp[1]]);
int dot2 = dot(X[tmp[1]],Y[tmp[1]],X[tmp[3]],Y[tmp[3]],X[tmp[2]],Y[tmp[2]]);
int dot3 = dot(X[tmp[2]],Y[tmp[2]],X[tmp[0]],Y[tmp[0]],X[tmp[3]],Y[tmp[3]]);
int dot4 = dot(X[tmp[3]],Y[tmp[3]],X[tmp[1]],Y[tmp[1]],X[tmp[0]],Y[tmp[0]]);
if(dis1>0&&dis1==dis2&&dis2==dis3&&dis3==dis4&&dot1==0&&dot2==0&&dot3==0&&dot4==0)
flag=1;
}while(next_permutation(tmp.begin(),tmp.end()));
if(flag)Ans=min(Ans,i+j+k+t);
}
}
}
}
if(Ans==10000)cout<<"-1"<<endl;
else cout<<Ans<<endl;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)solve();
return 0;
}
D. Flowers
题意
现在给你一堆花,有红花和白花,只有连续的k朵白花放在一起,才会觉得好看。
现在给你t个询问,问你摆放长度为l到r的好看的摆放方法种类有多少种
题解
预处理dp之后,利用前缀和进行O(1)回答就好了
我一开始写的dp是,dp[i][0]表示长度为i,结尾是红花的方案数,dp[i][1]表示结尾为白花的方案数,dp方程写完的时候,才发现这俩转移方程一样的……
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
const long long mod = 1e9+7;
int t,k,l,r;
long long dp[maxn][2];
int main(){
scanf("%d%d",&t,&k);
dp[0][0]=1;
for(int i=1;i<=100000;i++){
dp[i][0]=(dp[i-1][0]+dp[i-1][1])%mod;
if(i>=k)dp[i][1]=(dp[i-k][0]+dp[i-k][1])%mod;
}
dp[0][0]=0;
for(int i=1;i<=100000;i++)
(dp[i][0]+=dp[i-1][0])%=mod,
(dp[i][1]+=dp[i-1][1])%=mod;
for(int i=1;i<=t;i++){
int l,r;
scanf("%d%d",&l,&r);
printf("%lld\n",((dp[r][0]+dp[r][1]-dp[l-1][1]-dp[l-1][0])%mod+mod)%mod);
}
}
E - Pillars
题意
让你找到最长的子序列,满足abs(h[i]-h[i-1])>=d
题解
显然就和最长上升子序列一个道理,把绝对值拆开之后,用一个线段树去维护就好了
注意要离散化
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+7;
typedef int SgTreeDataType;
struct treenode
{
int L , R ;
SgTreeDataType sum , lazy;
void updata(SgTreeDataType v)
{
sum = v;
lazy = v;
}
};
treenode tree[maxn*4];
inline void push_down(int o)
{
SgTreeDataType lazyval = tree[o].lazy;
if(lazyval==0)return;
tree[2*o].updata(lazyval) ; tree[2*o+1].updata(lazyval);
tree[o].lazy = 0;
}
inline void push_up(int o)
{
tree[o].sum = max(tree[2*o].sum , tree[2*o+1].sum);
}
inline void build_tree(int L , int R , int o)
{
tree[o].L = L , tree[o].R = R,tree[o].sum = tree[o].lazy = 0;
if (R > L)
{
int mid = (L+R) >> 1;
build_tree(L,mid,o*2);
build_tree(mid+1,R,o*2+1);
}
}
inline void updata(int QL,int QR,SgTreeDataType v,int o)
{
int L = tree[o].L , R = tree[o].R;
if (QL <= L && R <= QR) tree[o].updata(v);
else
{
push_down(o);
int mid = (L+R)>>1;
if (QL <= mid) updata(QL,QR,v,o*2);
if (QR > mid) updata(QL,QR,v,o*2+1);
push_up(o);
}
}
inline SgTreeDataType query(int QL,int QR,int o)
{
int L = tree[o].L , R = tree[o].R;
if (QL <= L && R <= QR) return tree[o].sum;
else
{
push_down(o);
int mid = (L+R)>>1;
SgTreeDataType res = 0;
if (QL <= mid) res=max(res,query(QL,QR,2*o));
if (QR > mid) res=max(res,query(QL,QR,2*o+1));
push_up(o);
return res;
}
}
int n,dp[maxn];
long long h[maxn],d;
vector<long long>V;
map<long long,int>H;
int main()
{
scanf("%d%lld",&n,&d);
for(int i=1;i<=n;i++)
{
scanf("%lld",&h[i]);
V.push_back(h[i]);
V.push_back(h[i]-d);
V.push_back(h[i]+d);
}
sort(V.begin(),V.end());
V.erase(unique(V.begin(),V.end()),V.end());
for(int i=0;i<V.size();i++)
H[V[i]]=i+1;
build_tree(1,V.size()+5,1);
int Ans=0,Ans2=0;
for(int i=1;i<=n;i++){
dp[i]=max(query(1,H[h[i]-d],1),query(H[h[i]+d],V.size()+5,1))+1;
if(dp[i]>Ans){
Ans=dp[i];
Ans2=i;
}
updata(H[h[i]],H[h[i]],dp[i],1);
}
cout<<Ans<<endl;
vector<int>tmp;
tmp.push_back(Ans2);
for(int i=Ans2;i;i--){
if(dp[i]==Ans-1&&abs(h[i]-h[Ans2])>=d){
Ans2=i;
Ans--;
tmp.push_back(Ans2);
}
}
reverse(tmp.begin(),tmp.end());
for(int i=0;i<tmp.size();i++)
cout<<tmp[i]<<" ";
cout<<endl;
}
F - Ant colony
题意
查询区间gcd是多少,且查询区间有多少个数等于这个gcd
题解
线段树去维护区间gcd是什么,然后用二分去找到区间有多少个这个数
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+7;
typedef int SgTreeDataType;
struct treenode
{
int L , R ;
SgTreeDataType sum , lazy;
void updata(SgTreeDataType v)
{
sum = v;
lazy = v;
}
};
int gcd(int a,int b){
if(b==0)return a;
return gcd(b,a%b);
}
treenode tree[maxn*4];
inline void push_down(int o)
{
}
inline void push_up(int o)
{
tree[o].sum = gcd(tree[o<<1].sum,tree[o<<1|1].sum);
}
inline void build_tree(int L , int R , int o)
{
tree[o].L = L , tree[o].R = R,tree[o].sum = tree[o].lazy = 0;
if (R > L)
{
int mid = (L+R) >> 1;
build_tree(L,mid,o*2);
build_tree(mid+1,R,o*2+1);
}
}
inline void updata(int QL,int QR,SgTreeDataType v,int o)
{
int L = tree[o].L , R = tree[o].R;
if (QL <= L && R <= QR) tree[o].updata(v);
else
{
push_down(o);
int mid = (L+R)>>1;
if (QL <= mid) updata(QL,QR,v,o*2);
if (QR > mid) updata(QL,QR,v,o*2+1);
push_up(o);
}
}
inline SgTreeDataType query(int QL,int QR,int o)
{
int L = tree[o].L , R = tree[o].R;
if (QL <= L && R <= QR) return tree[o].sum;
else
{
push_down(o);
int mid = (L+R)>>1;
SgTreeDataType res = 0;
if (QL <= mid) res=gcd(res,query(QL,QR,2*o));
if (QR > mid) res=gcd(res,query(QL,QR,2*o+1));
push_up(o);
return res;
}
}
int n,m,a[maxn];
pair<int,int>p[maxn];
int main()
{
scanf("%d",&n);
build_tree(1,n,1);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
updata(i,i,a[i],1);
p[i].first=a[i];
p[i].second=i;
}
scanf("%d",&m);
sort(p+1,p+1+n);
for(int i=1;i<=m;i++){
int l,r;
scanf("%d%d",&l,&r);
int pp=query(l,r,1);
int L=lower_bound(p+1,p+1+n,make_pair(pp,l))-(p+1);
int R=lower_bound(p+1,p+1+n,make_pair(pp,r+1))-(p+1);
printf("%d\n",(r-l+1)-(R-L));
}
}